/*
	Written By Pradipna Nepal
	www.pradsprojects.com

	Copyright (C) 2012 Prads Projects
	Please read COPYING.txt included along with this source code for more detail.
	If not included, see http://www.gnu.org/licenses/
*/

#include "libTokenModule.h"

TokenLineTypes getLineType(const vector<Token> *tokens, unsigned int index);

bool ModuleSeparator::separateModules(const vector<Token> *tokens, vector<TokenModule> *modOut) {
	unsigned int moduleID = MODULE_ID_MAIN, scopeLevel = 0,	tokensSize = tokens->size();
	TokenModule tempModule;

	//Push back global declaration area if there is none
	if (modOut->size() == 0) { 
		tempModule.id = MODULE_ID_MAIN;
		tempModule.name = string();
		modOut->push_back(tempModule);
	}

	unsigned int tokenCounter = 0;
	TokenLines tempTL;
	
	while (true) {
		tempTL.lineType = getLineType(tokens, tokenCounter);

		switch (tempTL.lineType) {
			case TL_NONE:
				{
					string err;
					err = "Unexpected token: " + (*tokens)[tokenCounter].getValue();
					printError(ERROR_SYNTAX, err.c_str());
					return false;
				}
			//Search for semi colon
			case TL_FUNCTION_CALL:
			case TL_ASSIGNMENT:
			case TL_VAR_DECLARE:
			case TL_CONST_DECLARE:
			case TL_CONST_STRING_DECLARE:
			case TL_STRUCT_DECLARE:
			case TL_ARRAY_ASSIGNMENT:
			case TL_INBUILT_FUNCTION_CALL:
			case TL_IMAGE_DECLARE:
				while ((*tokens)[tokenCounter].getToken() != TOKEN_SEMICOLON) {
					tempTL.tokens.push_back((*tokens)[tokenCounter++]);
				}
				tempTL.tokens.push_back((*tokens)[tokenCounter]);
				(*modOut)[moduleID].lines.push_back(tempTL);
				break;
			//Search for open curly braces
			case TL_CONDITION:
			case TL_STRUCT:
lookForOpenCurlyBrace:
				while ((*tokens)[tokenCounter].getToken() != TOKEN_OPENCURLYBRACKET) {
					tempTL.tokens.push_back((*tokens)[tokenCounter++]);
				}
				tempTL.tokens.push_back((*tokens)[tokenCounter]);
				(*modOut)[moduleID].lines.push_back(tempTL);
				++scopeLevel;
				break;
			case TL_FUNTION_DECLARE:
				moduleID = modOut->size();
				tempModule.id = moduleID;
				tempModule.name = (*tokens)[tokenCounter + 1].getValue();
				modOut->push_back(tempModule);
				goto lookForOpenCurlyBrace;
			case TL_CLOSE_SCOPE:
				--scopeLevel;
				if (scopeLevel == 0) {
					moduleID = MODULE_ID_MAIN;
				} else {
					tempTL.tokens.push_back((*tokens)[tokenCounter]);
					(*modOut)[moduleID].lines.push_back(tempTL);
				}
		}

		++tokenCounter;
		if (tokenCounter >= tokensSize) break;
		tempTL.tokens.clear();
	}

	return  true;
}

TokenLineTypes getLineType(const vector<Token> *tokens, unsigned int index) {
	switch ((*tokens)[index].getToken()) {
		case TOKEN_IDENTIFIER:
			if ((*tokens)[++index].getDescription() == OPERATOR_ASSIGN) {
				return TL_ASSIGNMENT;
			} else if ((*tokens)[index].getToken() == TOKEN_OPENROUNDBRACKET) {
				index += 2;
				if ((*tokens)[index].getToken() == TOKEN_SEMICOLON) {
					return TL_FUNCTION_CALL;
				} else if ((*tokens)[index].getToken() == TOKEN_OPENCURLYBRACKET) {
					return TL_FUNTION_DECLARE;
				}
			} else if ((*tokens)[index].getToken() == TOKEN_OPENSQUAREBRACKET) {
				return TL_ARRAY_ASSIGNMENT;
			} else if ((*tokens)[++index].getToken() == TOKEN_SEMICOLON) {
				return TL_STRUCT_DECLARE;
			}
			break;
		case TOKEN_KEYWORD:
			switch ((*tokens)[index].getDescription()) {
				case KW_VOID:
					return TL_FUNTION_DECLARE;
				case KW_FOR:
				case KW_IF:
				case KW_WHILE:
				case KW_SWITCH:
				case KW_CASE:
				case KW_DEFAULT:
				case KW_ELSE:				
					return TL_CONDITION;
				case KW_VAR:
					if ((*tokens)[index + 2].getToken() == TOKEN_OPENROUNDBRACKET)
						return TL_FUNTION_DECLARE;
					else
						return TL_VAR_DECLARE;
				case KW_CONST:
					return TL_CONST_DECLARE;
				case KW_CONSTSTRING:
					return TL_CONST_STRING_DECLARE;
				case KW_STRUCT:
					return TL_STRUCT;
				case KW_BGC_N:
				case KW_PRINT:
				case KW_DRAW:
				case KW_CLS:
				case KW_VBLANK:
				case KW_FLIP:
					return TL_INBUILT_FUNCTION_CALL;
				case KW_IMAGE:
					return TL_IMAGE_DECLARE;
			}
		case TOKEN_OPERATOR:
			if ((*tokens)[index].getDescription() == OPERATOR_MUL)
				return TL_ASSIGNMENT;
			else
				return TL_NONE;
		case TOKEN_CLOSECURLYBRACKET:
			return TL_CLOSE_SCOPE;
	}

	return TL_NONE;
}